package com.topvision.camerasdk.camera.util;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Point;
import android.hardware.Camera;
import android.media.MediaMetadataRetriever;
import android.media.ThumbnailUtils;
import android.os.Build;
import android.text.TextUtils;
import android.util.Log;
import android.view.Display;

import com.topvision.camerasdk.camera.CameraActivity;
import com.topvision.camerasdk.camera.CameraConstants;
import com.topvision.camerasdk.video.util.VideoConstant;
import com.topvision.commomsdk.commom.Album;
import com.topvision.commomsdk.uitl.AndroidUtils;
import com.topvision.commomsdk.uitl.FileUtil;
import com.topvision.voicesdk.VoiceSdk;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.regex.Pattern;

/**
 * User: jack(jackgu@topvision-cv.com)
 * Date: 2016-11-21
 * Time: 15:53
 */
public class CameraUtil {

    private static final String TAG = CameraUtil.class.getSimpleName();
    private static final Pattern COMMA_PATTERN = Pattern.compile(",");

    public static Point getCameraResolution(Camera.Parameters parameters, Point screenResolution) {

        String previewSizeValueString = parameters.get("preview-size-values");
        // saw this on Xperia
        if (previewSizeValueString == null) {
            previewSizeValueString = parameters.get("preview-size-value");
        }

        Point cameraResolution = null;

        if (previewSizeValueString != null) {
            Log.d(TAG, "preview-size-values parameter: " + previewSizeValueString);
            cameraResolution = findBestPreviewSizeValue(previewSizeValueString, screenResolution);
        }

        if (cameraResolution == null) {
            // Ensure that the camera resolution is a multiple of 8, as the screen may not be.
            cameraResolution = new Point(
                    (screenResolution.x >> 3) << 3,
                    (screenResolution.y >> 3) << 3);
        }

        return cameraResolution;
    }


    private static Point findBestPreviewSizeValue(CharSequence previewSizeValueString, Point screenResolution) {
        int bestX = 0;
        int bestY = 0;
        int diff = Integer.MAX_VALUE;
        for (String previewSize : COMMA_PATTERN.split(previewSizeValueString)) {

            previewSize = previewSize.trim();
            int dimPosition = previewSize.indexOf('x');
            if (dimPosition < 0) {
                Log.w(TAG, "Bad preview-size: " + previewSize);
                continue;
            }

            int newX;
            int newY;
            try {
                newX = Integer.parseInt(previewSize.substring(0, dimPosition));
                newY = Integer.parseInt(previewSize.substring(dimPosition + 1));
            } catch (NumberFormatException nfe) {
                Log.w(TAG, "Bad preview-size: " + previewSize);
                continue;
            }

            int newDiff = Math.abs(newX - screenResolution.x) + Math.abs(newY - screenResolution.y);
            if (newDiff == 0) {
                bestX = newX;
                bestY = newY;
                break;
            } else if (newDiff < diff) {
                bestX = newX;
                bestY = newY;
                diff = newDiff;
            }

        }

        if (bestX > 0 && bestY > 0) {
            return new Point(bestX, bestY);
        }
        return null;
    }


    /**
     * 获取一个目录下最新的一个file文件
     *
     * @param @param  folderPath
     * @param @return 设定文件
     * @return File 返回类型
     * @throws
     * @Title: getNewestFile
     * @Description:
     */
    public static File getNewestFile(String folderPath) {
        File folder = new File(folderPath);
        if (!folder.exists()) {
            folder.mkdirs();
        }
        File[] files = folder.listFiles();
        if (files != null && files.length > 0) {
            // 按时间排序
            Arrays.sort(files, new ComparedByLastModified());
            for (File file : files) {
                // 图片的话则查询的是图片文件，拿的是縮略图
                if (file.getPath().contains(CameraActivity.THUMBNAIL_NAME) && file.length() > 0) {
                    return file;
                }
            }
        }

        return null;

    }

    /**
     * 获取最新的视频缩略图
     * create at 2017/1/16 17:14
     */
    public static File getNewestVideoFile(Context context) {
        File folder = new File(CameraConstants.THUMBNAIL_FOLDER);
        File[] files = null;
        if (!folder.exists()) {
            folder.mkdirs();
            AndroidUtils.fileScan(context, folder.getPath());
        }
        files = folder.listFiles();
        //有外置内存卡
        String extSdcard = AndroidUtils.getExtSDCardPath(context);
        if (!TextUtils.isEmpty(extSdcard)) {
            File extFolder = new File(extSdcard + VideoConstant.MEDIA_FOLDER);
            if (!extFolder.exists()) {
                extFolder.mkdirs();
                AndroidUtils.fileScan(context, extFolder.getAbsolutePath());
            }
            if (extFolder.isDirectory()) {
                files = concat(files, extFolder.listFiles());
            }
        }
        if (files != null && files.length > 0) {
            // 按时间排序
            Arrays.sort(files, new ComparedByLastModified());
            for (File file : files) {
                if (file.getPath().contains("video") && file.length() > 0) {
                    return file;
                }
            }
        }

        return null;

    }

    /**
     * 获取照片一览缩略图
     *
     * @param context
     * @return
     */
    public static ArrayList<Album> getPhotoList(Context context) {
        //获取内置和外置sdcard中图片文件数组
        File[] files = getVideoFiles(context, VideoConstant.ABLUM_TYPE_PHOTO);
        Arrays.sort(files, new ComparedByLastModified());
        ArrayList<Album> albumList = new ArrayList<>();
        for (File file : files) {
            if (!file.exists() || file.length() == 0) {
                continue;
            }
            String path = file.getAbsolutePath();
            String folderPath = getFolderPath(path);
            if (path.endsWith(".doc")
                    || path.endsWith(".xls")
                    || path.endsWith(".pdf")) {

                Album album = new Album(file, path);
                album.setThumbnailPath("document");
                albumList.add(album);

            } else {
                File thumbnailFolder = new File(CameraConstants.THUMBNAIL_FOLDER);
                if (!thumbnailFolder.exists()) {
                    thumbnailFolder.mkdirs();
                }
                if (path.endsWith(".jpg")
                        || path.endsWith(".jpeg")
                        || path.endsWith(".png")
                        || path.endsWith(".bmp")) {
//                    String originFilePath = path.replace("-thumbnail", "");
                    String[] split = path.split("\\/");
                    String name = split[split.length - 1];
                    String thumbnailPath = CameraConstants.THUMBNAIL_FOLDER + name.replace(".", "-thumbnail.");
                    File thumbnailNameFile = new File(thumbnailPath);
                    if (!thumbnailNameFile.exists()) {
                        Bitmap thumbnailBitmap = getThumbnailBitmap(path);
                        saveThumbnail(thumbnailBitmap, thumbnailNameFile);
                    }
                    Album album = new Album(file, path);
                    album.setThumbnailPath(thumbnailPath);
                    albumList.add(album);
                }
                /*//找到该目录下的所有缩略图地址
                if (path.endsWith("thumbnail.jpg")
                        || path.endsWith("thumbnail.jpeg")
                        || path.endsWith("thumbnail.png")
                        || path.endsWith("thumbnail.bmp")) {
                    //获取原文件路径
                    String originFilePath = path.replace("-thumbnail", "");
                    Album album = new Album(file, originFilePath);
                    album.setThumbnailPath(path);
                    albumList.add(album);

                }
                //如果查找到是原文件,如果该原文件的缩略图不存在,则需要生成一个缩略图
                else {
                    String filename = file.getName();
                    String[] split = filename.split("\\.");
//                    String thumbnailName = split[0] + "-thumbnail.jpg";
                    String thumbnailName = split[0] + "-thumbnail." + split[1];
                    File thumbnailNameFile = new File(folderPath + File.separator + thumbnailName);
                    if (!thumbnailNameFile.exists()) {
                        Bitmap ThumbnailBitmap = getThumbnailBitmap(path);
                        saveThumbnail(ThumbnailBitmap, thumbnailName, folderPath);
                        Album album = new Album(file, path);
                        album.setThumbnailPath(folderPath + File.separator + thumbnailName);
                        albumList.add(album);
                    }
                }*/
            }
        }
        return albumList;
    }

    /**
     * 通过文件路径,获取其上级目录
     * create at 2017/3/6 16:35
     */
    private static String getFolderPath(String path) {
        int index = path.lastIndexOf("/");
        return path.substring(0, index);
    }

    /**
     * 获取拍照视频列表
     * create at 2016/11/21 14:29
     *
     * @author jack
     */
    public static ArrayList<Album> getVideoList(Context context) {
        ArrayList<Album> albumList = new ArrayList<>();
        File[] files = getVideoFiles(context, VideoConstant.ABLUM_TYPE_MEDIA);
        //排序。按文件名称时间戳排序
        Arrays.sort(files, new ComparedByLastModified());
        //放入到集合
        for (File file : files) {
            if (!file.exists() || file.length() == 0) {
                continue;
            }
            String path = file.getAbsolutePath();
            if (path.endsWith(".mp4")) {
                try {
                    MediaMetadataRetriever mmr = new MediaMetadataRetriever();
                    mmr.setDataSource(path);
                    String duration = mmr
                            .extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
                    mmr.release();
                    if (Long.parseLong(duration) > 0) {
                        Album album = new Album(file, path, duration);
                        albumList.add(album);
//                        Message message = new Message();
//                        message.what = MyAblumActivity.HANDLER_UPDATE_LIST;
//                        message.obj = albumList;
//                        handler.sendMessage(message);
                    }
                } catch (Exception e) {
                    //刪除视频和其缩略图
                    String jpgPath = path.replace("mp4", "jpg");
                    FileUtil.removeFile(context, path);
                    FileUtil.removeFile(context, jpgPath);
                }

            }

        }

        return albumList;
    }


    // 根据文件修改时间进行比较的内部类
    static class ComparedByLastModified implements Comparator<File> {

        public int compare(File f1, File f2) {
            // 这个做法只是为之前拍过照的一些设备添加的条件
            if (f1.getName().indexOf("thumbnail") > 0) {
                long diff = f1.lastModified() - f2.lastModified();
                if (diff > 0) {
                    return -1;
                } else if (diff == 0) {
                    return 0;
                } else {
                    return 1;
                }
            }

            if (f2.getName().indexOf("thumbnail") > 0) {
                long diff = f1.lastModified() - f2.lastModified();
                if (diff > 0) {
                    return -1;
                } else if (diff == 0) {
                    return 0;
                } else {
                    return 1;
                }
            }

            long diff = getFileNumber(f1) - getFileNumber(f2);
            if (diff > 0) {
                return -1;
            } else if (diff == 0) {
                return 0;
            } else {
                return 1;
            }
        }

        private long getFileNumber(File file) {
            int i = 0;
            String fileName = file.getName();
            if (fileName.contains("doc") || fileName.contains("pdf") || fileName.contains("xls")) {
                i = i + 1;
                return Long.parseLong(String.valueOf(i));
            } else {
                if (!TextUtils.isEmpty(fileName)) {
                    int index = fileName.indexOf(".");
                    try {
                        if (index > -1) {
                            return Long.parseLong(fileName.substring(0, index));
                        }

                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                }
            }
            /*if (!TextUtils.isEmpty(fileName)) {
                int index = fileName.indexOf(".");
                return Long.parseLong(fileName.substring(0, index));
            }*/
            return i;
        }
    }


    public static Bitmap getThumbnailBitmap(String imagePath) {
        BitmapFactory.Options opt = new BitmapFactory.Options();
        opt.inPurgeable = true;
        opt.inSampleSize = 2;
        //获取资源图片
        return BitmapFactory.decodeFile(imagePath, opt);
    }

    public static void saveThumbnail(Bitmap mBitmap, File file) {
        FileOutputStream fOut = null;
        try {
            fOut = new FileOutputStream(file);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        if (mBitmap != null) {
            mBitmap.compress(Bitmap.CompressFormat.JPEG, 100, fOut);
        }
        try {
            fOut.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            fOut.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /*************************************************新填方法  16/12/13 *********************************************/

     /* */

    /**
     * 获取视频缩略图
     *
     * @param @param  filePath
     * @param @param  width
     * @param @param  height
     * @param @param  kind
     * @param @return
     * @return Bitmap
     * @throws
     * @Title: getVidioBitmap
     * @Description:
     */
    public static Bitmap getVidioBitmap(String filePath, int width, int height,
                                        int kind) {
        // 定義一個Bitmap對象bitmap；
        Bitmap bitmap = null;

        // ThumbnailUtils類的截取的圖片是保持原始比例的，但是本人發現顯示在ImageView控件上有时候有部分沒顯示出來；
        // 調用ThumbnailUtils類的靜態方法createVideoThumbnail獲取視頻的截圖；
        bitmap = ThumbnailUtils.createVideoThumbnail(filePath, kind);
        // 調用ThumbnailUtils類的靜態方法extractThumbnail將原圖片（即上方截取的圖片）轉化為指定大小；
        // 最後一個參數的具體含義我也不太清楚，因為是閉源的；
        bitmap = ThumbnailUtils.extractThumbnail(bitmap, width, height,
                ThumbnailUtils.OPTIONS_RECYCLE_INPUT);

        // 放回bitmap对象；
        return bitmap;
    }


    /**
     * 判断语音服务是否在运行 控制语音开关
     */
    public static void controlVocie(Context context, boolean voiceServiceIsRun) {
        // voiceServiceIsRun    true 为语音服务正在运行  false 为语音服务没有运行
        if (voiceServiceIsRun && context.getClass().getName().equals(VideoConstant.MediaRecorderActivity)) {
            VoiceSdk.stopVoiceTrack(context);
        } else {
            /*if(context.getClass().getName().equals(VideoConstant.MediaRecorderActivity)){
                TvSdk.startVoiceTrack(context,10);
            }else{

            }*/
        }
    }

    public static boolean fileIsExists(String jpgPath) {
        try {
            File f = new File(jpgPath);
            if (!f.exists()) {
                return false;
            }

        } catch (Exception e) {
            // TODO: handle exception
            return false;
        }
        return true;
    }

    /*************************************************
     * End
     *********************************************/


    public static <T> T[] concat(T[] first, T[] second) {
        T[] result = Arrays.copyOf(first, first.length + second.length);
        System.arraycopy(second, 0, result, first.length, second.length);
        return result;
    }


    /**
     * 获取视频文件
     * create at 2017/2/17 10:58
     */
    public static File[] getVideoFiles(Context context, String type) {
        String innerSdFolder = "";
        String extSdFolder = "";
        String extSdcard = AndroidUtils.getExtSDCardPath(context);
        if (VideoConstant.ABLUM_TYPE_MEDIA.equals(type)) {
            innerSdFolder = VideoConstant.mediaFolderPath;
            extSdFolder = extSdcard + VideoConstant.MEDIA_FOLDER;
        } else if (VideoConstant.ABLUM_TYPE_PHOTO.equals(type)) {
            innerSdFolder = VideoConstant.photoFolderPath;
            extSdFolder = extSdcard + VideoConstant.PHOTO_FOLDER;
        }
        File sdcardFolder = new File(innerSdFolder);
        if (!sdcardFolder.exists()) {
            sdcardFolder.mkdirs();
        }
        File[] files = sdcardFolder.listFiles();
        //有外置内存卡
        if (!TextUtils.isEmpty(extSdcard)) {
            File extFolder = new File(extSdFolder);
            if (!extFolder.exists()) {
                extFolder.mkdirs();
                AndroidUtils.fileScan(context, extFolder.getAbsolutePath());
            }
            if (extFolder.isDirectory()) {
                files = concat(files, extFolder.listFiles());
            }
        }
        return files;
    }


    /**
     * 刪除较早的一些视频和他的缩略图
     *
     * @param count 个数
     *              create at 2017/2/17 11:24
     */
    public static void removeEarlyVideos(Context context, int count) {
        File[] files = getVideoFiles(context, VideoConstant.ABLUM_TYPE_MEDIA);
        //如果剩余的文件大于count个数,则删除count个数的视频文件,当剩余个数的文件小于count个数,则只需要删除files.length长度。
        count = files.length >= count ? count : files.length;
        for (int i = 0; i < count; i++) {
            File file = files[i];
            if (file.exists()) {
                try {
                    String filename = file.getName();
                    //获得该文件的缩略图
                    String thumbnailName = filename.split("\\.")[0] + "-thumbnail.jpg";
                    FileUtil.removeFile(context, thumbnailName);
//                    File thumbnailFile = new File(thumbnailName);
//                    file.delete();
//                    thumbnailFile.delete();
                } catch (Exception e) {
                    e.printStackTrace();
                }

            }
        }
    }


    /**
     * 判断是否支持camera的参数
     * create at 2017/3/6 17:20
     */
    public static boolean isSupported(String value, List<String> supported) {
        return supported == null ? false : supported.indexOf(value) >= 0;
    }


    public static Camera.Size getDesiredPreviewSize(Activity mActivity, Camera.Parameters mParameters) {
        int mDesiredPreviewWidth = 0;
        int mDesiredPreviewHeight = 0;
        List<Camera.Size> sizes = mParameters.getSupportedPreviewSizes();
        Display d = mActivity.getWindowManager().getDefaultDisplay();
        Camera.Size optimalSize = getOptimalPreviewSize(mActivity, sizes,
                (double) d.getWidth() / d.getHeight());
        mDesiredPreviewWidth = optimalSize.width;
        mDesiredPreviewHeight = optimalSize.height;
        Log.v(TAG, "mDesiredPreviewWidth=" + mDesiredPreviewWidth +
                ". mDesiredPreviewHeight=" + mDesiredPreviewHeight);
        return optimalSize;

    }

    public static Camera.Size getOptimalPreviewSize(Activity mActivity,
                                                    List<Camera.Size> sizes, double targetRatio) {
        // Use a very small tolerance because we want an exact match.
        final double ASPECT_TOLERANCE = 0.001;
        if (sizes == null) return null;

        Camera.Size optimalSize = null;
        double minDiff = Double.MAX_VALUE;

        // Because of bugs of overlay and layout, we sometimes will try to
        // layout the viewfinder in the portrait orientation and thus get the
        // wrong size of preview surface. When we change the preview size, the
        // new overlay will be created before the old one closed, which causes
        // an exception. For now, just get the screen size.
        Point point = getDefaultDisplaySize(mActivity, new Point());
        int targetHeight = Math.min(point.x, point.y);
        // Try to find an size match aspect ratio and size
        for (Camera.Size size : sizes) {
            double ratio = (double) size.width / size.height;
            if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
            if (Math.abs(size.height - targetHeight) < minDiff) {
                optimalSize = size;
                minDiff = Math.abs(size.height - targetHeight);
            }
        }
        // Cannot find the one match the aspect ratio. This should not happen.
        // Ignore the requirement.
        if (optimalSize == null) {
            Log.w(TAG, "No preview size match the aspect ratio");
            minDiff = Double.MAX_VALUE;
            for (Camera.Size size : sizes) {
                if (Math.abs(size.height - targetHeight) < minDiff) {
                    optimalSize = size;
                    minDiff = Math.abs(size.height - targetHeight);
                }
            }
        }
        return optimalSize;
    }


    @SuppressWarnings("deprecation")
    private static Point getDefaultDisplaySize(Activity activity, Point size) {

        Display d = activity.getWindowManager().getDefaultDisplay();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
            d.getSize(size);
        } else {
            size.set(d.getWidth(), d.getHeight());
        }
        return size;
    }


    public static Camera.Size getMaxPreviewSize(Camera.Parameters parameters) {
        if (parameters != null) {
            return parameters.getSupportedPreviewSizes().get(0);
        }
        return null;
    }


    /**
     * 通过对比得到与宽高比最接近的预览尺寸（如果有相同尺寸，优先选择）
     *
     * @param isPortrait    是否竖屏
     * @param surfaceWidth  需要被进行对比的原宽
     * @param surfaceHeight 需要被进行对比的原高
     * @param preSizeList   需要对比的预览尺寸列表
     * @return 得到与原宽高比例最接近的尺寸
     */
    public static Camera.Size getCloselyPreSize(boolean isPortrait, int surfaceWidth, int surfaceHeight, List<Camera.Size> preSizeList) {
        int reqTmpWidth;
        int reqTmpHeight;
        // 当屏幕为垂直的时候需要把宽高值进行调换，保证宽大于高
        if (isPortrait) {
            reqTmpWidth = surfaceHeight;
            reqTmpHeight = surfaceWidth;
        } else {
            reqTmpWidth = surfaceWidth;
            reqTmpHeight = surfaceHeight;
        }
        //先查找preview中是否存在与surfaceview相同宽高的尺寸
        for (Camera.Size size : preSizeList) {
            if ((size.width == reqTmpWidth) && (size.height == reqTmpHeight)) {
                return size;
            }
        }

        // 得到与传入的宽高比最接近的size
        float reqRatio = ((float) reqTmpWidth) / reqTmpHeight;
        float curRatio, deltaRatio;
        float deltaRatioMin = Float.MAX_VALUE;
        Camera.Size retSize = null;
        for (Camera.Size size : preSizeList) {
            curRatio = ((float) size.width) / size.height;
            deltaRatio = Math.abs(reqRatio - curRatio);
            if (deltaRatio < deltaRatioMin) {
                deltaRatioMin = deltaRatio;
                retSize = size;
            }
        }

        return retSize;
    }
}